<template>
  <el-upload
    ref="uploadRef"
    v-model:file-list="fileList"
    v-loading="isLoading"
    :accept="accept"
    :auto-upload="false"
    class="image-uploader"
    :class="{ 'image-uploader-avatar': !multiple }"
    :limit="limit"
    :list-type="isShowImgList ? 'picture-card' : 'text'"
    :multiple="multiple"
    :on-change="handleChange"
    :show-file-list="isShowImgList"
  >
    <template #trigger>
      <slot v-if="multiple" name="default">
        <el-icon v-if="isShowImgList"><Plus /></el-icon>
        <el-button v-else type="primary">选择文件</el-button>
      </slot>
      <slot v-else name="default">
        <div v-if="type === 'avatar'" class="avatar">
          <img v-if="imgUrl || defaultImageUrl" class="avatar-img" :src="imgUrl || defaultImageUrl" />
          <span v-else>上传</span>
        </div>
        <el-button v-else type="primary">上传</el-button>
      </slot>
    </template>
    <div v-if="!multiple && type === 'avatar' && (imgUrl || defaultImageUrl)">
      <el-button size="small" type="primary" @click="handlePreview()"> 预览 </el-button>
    </div>
    <template v-if="multiple">
      <slot name="submit">
        <el-button class="submit-btn" type="primary" @click="uploadImg"> 上传至服务器 </el-button>
      </slot>
    </template>
    <template #file="{ file }">
      <slot>
        <div name="file">
          <img alt="" class="el-upload-list__item-thumbnail" :src="file.url" />
          <span class="el-upload-list__item-actions">
            <span class="el-upload-list__item-preview" @click="handlePreview(file)">
              <el-icon><zoom-in /></el-icon>
            </span>
            <span class="el-upload-list__item-delete" @click="handleRemove(file)">
              <el-icon><Delete /></el-icon>
            </span>
          </span>
        </div>
      </slot>
    </template>
    <el-dialog v-model="dialogVisible">
      <img alt="Preview Image" class="preview-img" :src="dialogImageUrl" />
    </el-dialog>
  </el-upload>
</template>

<script>
import { uploadUrl } from "@/api/mains.ts";
import { staticURL } from "@/config";
import { failMsg } from "@/utils/MessageUtils";

export default {
  name: "UploadImage",
  props: {
    accept: {
      type: String,
      default: "image/png, image/jpeg"
    },
    url: {
      type: String,
      default: ""
    },
    size: {
      type: Number,
      default: 0
    },
    limit: {
      type: Number,
      default: null
    },
    type: {
      type: String,
      default: ""
    },
    multiple: {
      type: Boolean,
      default: false
    },
    isDoDel: {
      type: Boolean,
      default: true
    },
    isShowImgList: {
      type: Boolean,
      default: false
    },
    uploadParams: {
      type: Object,
      default: () => {
        return {
          moduleName: "",
          entityId: ""
        };
      }
    },
    delUrl: {
      type: String,
      default: "file/delete?filePath="
    },
    imageUrl: {
      type: String,
      default: ""
    },
    defaultFileList: {
      type: Array,
      default: () => []
    }
  },
  emits: {
    "on-submit": null,
    "on-error": null,
    "on-success": null,
    "on-del": null,
    "del-success": null,
    "on-change-file": null
  },

  setup(props, { emit, expose }) {
    const state = reactive({
      imgUrl: "",
      dialogImageUrl: "",
      dialogVisible: false,
      isLoading: false
    });
    const fileList = ref(props.defaultFileList);

    const defaultImageUrl = computed(() => {
      const url = props.imageUrl ? `${staticURL}\\${props.imageUrl}` : "";
      return url;
    });

    const actionUrl = computed(() => {
      const { url, multiple } = props;
      if (url) return url;
      const currenUrl = multiple ? "system/file/uploadMultiImgs" : "system/file/uploadImg";
      return currenUrl;
    });

    const handleFileSize = file => {
      const { size } = file;
      if (props.size && size > props.size * 1024) {
        state.isLoading = false;
        failMsg(`文件大小不能超过${props.size}MB`);
        return true;
      }
      return false;
    };

    /**
     * 设置单个文件数据
     */
    const setSingleFileData = file => {
      const { raw } = file;
      const formdata = new FormData();
      const { uploadParams } = props;
      const keys = Object.keys(uploadParams);
      for (const item of keys) {
        formdata.append(item, uploadParams[item]);
      }
      formdata.append("file", raw);
      return formdata;
    };

    /**
     * 设置多个文件数据
     */
    const setMultipFileData = files => {
      const formdata = new FormData();
      files.map(item => {
        formdata.append("files", item.raw);
      });

      const { uploadParams } = props;
      const keys = Object.keys(uploadParams);
      for (const item of keys) {
        formdata.append(item, uploadParams[item]);
      }

      return formdata;
    };

    /**
     * 处理上传
     */
    const handleUpload = async files => {
      // if (!props.url) {
      //   emit('on-submit', files)
      // }
      state.isLoading = true;

      let formdata = "";

      if (!props.multiple) {
        const file = files;
        if (!files) return;
        const isMoreSize = handleFileSize(file);
        if (isMoreSize) {
          return;
        }

        // if (2 > 1) {
        //   failMsg("测试环境暂不支持上传图片");
        //   state.isLoading = false;
        //   return;
        // }

        formdata = setSingleFileData(file);
      } else {
        if (!files?.length) return;
        const isMoreSize = files.some(file => handleFileSize(file));
        if (isMoreSize) {
          return;
        }

        formdata = setMultipFileData(files);
      }

      const responseData = await uploadUrl(actionUrl.value, formdata);
      state.isLoading = false;
      const { data = {}, code } = responseData;
      if (code !== 200) {
        emit("on-error");
        return;
      }
      if (!props.multiple) {
        state.imgUrl = `${staticURL}\\${data.uri}`;
      }

      emit("on-success", data, fileList.value);
      emit("on-change-file", fileList.value);
    };

    const handleChange = file => {
      if (!props.multiple) handleUpload(file);
    };

    /**
     * 多图上传
     */
    const uploadImg = () => {
      const files = fileList.value.filter(item => item.raw);
      handleUpload(files);
    };

    const delImg = file => {
      const index = fileList.value.findIndex(item => item.uid === file.uid);
      fileList.value.splice(index, 1);
      emit("on-change-file", fileList.value);
    };

    const handlePreview = file => {
      const img = state.imgUrl || defaultImageUrl.value;
      state.dialogImageUrl = file ? file.url : img?.replace("-reduce", "");
      state.dialogVisible = true;
    };

    const handleRemove = async file => {
      if (!props.isDoDel) {
        emit("on-del", file);
        return;
      }
      delImg(file);
    };

    expose({ handlePreview, handleRemove });

    watch(
      () => props.defaultFileList,
      newVal => {
        fileList.value = newVal;
      },
      {
        deep: true
      }
    );

    return {
      ...toRefs(state),
      defaultImageUrl,
      fileList,
      actionUrl,
      handleUpload,
      handleChange,
      uploadImg,
      handlePreview,
      handleRemove
    };
  }
};
</script>
<style lang="scss" scoped>
.image-uploader {
  .submit-btn {
    margin-top: 15px;
  }
  :deep() {
    .el-upload-list {
      display: block;
    }
  }
  .preview-img {
    display: block;
    max-width: 100%;
    max-height: 60vh;
    margin: 0 auto;
  }
}
.image-uploader-avatar {
  display: flex;
  align-items: center;
}
.avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 50px;
  height: 50px;
  margin-right: 10px;
  overflow: hidden;
  background-color: #ffffff;
  border-radius: 25px;
  box-shadow: 0 0 10px #eeeeee;
  > img {
    width: 100%;
    height: 100%;
  }
  > span {
    font-size: 12px;
  }
}
</style>
